#(logfile /var/log/xen/xend.log)
#(loglevel DEBUG)
+# The Xen-API server configuration. (Please note that this server is available
+# as an UNSUPPORTED PREVIEW in Xen 3.0.4, and should not be relied upon).
+#
+# This value configures the ports, interfaces, and access controls for the
+# Xen-API server. Each entry in the list starts with either unix, a port
+# number, or an address:port pair. If this is "unix", then a UDP socket is
+# opened, and this entry applies to that. If it is a port, then Xend will
+# listen on all interfaces on that TCP port, and if it is an address:port pair,
+# then Xend will listen on the specified port, using the interface with the
+# specified address.
+#
+# The subsequent string gives the access control for the listener in question.
+# If this is missing or empty, then all connections are accepted.
+# Otherwise, this should be a space-separated sequence of regular expressions;
+# any host with a fully-qualified domain name or an IP address that matches one
+# of these regular expressions will be accepted.
+#
+# Example:
+#
+# Listen on TCP port 9363 on all interfaces, accepting connections only from
+# machines in example.com or localhost.
+# (xen-api-server ((9363 '^localhost$ example\\.com$')))
+#
+# Default:
+# (xen-api-server ((unix)))
+
#(xend-http-server no)
#(xend-unix-server no)
#(xend-tcp-xmlrpc-server no)
import SocketServer
import xmlrpclib, socket, os, stat
+from xen.web import connection
from xen.xend.XendLogging import log
try:
class XMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
protocol_version = "HTTP/1.1"
+ def __init__(self, hosts_allowed, request, client_address, server):
+ self.hosts_allowed = hosts_allowed
+ SimpleXMLRPCRequestHandler.__init__(self, request, client_address,
+ server)
+
# this is inspired by SimpleXMLRPCRequestHandler's do_POST but differs
# in a few non-trivial ways
# 1) we never generate internal server errors. We let the exception
# 2) we don't bother checking for a _dispatch function since we don't
# use one
def do_POST(self):
+ addrport = self.client_address
+ if not connection.hostAllowed(addrport, self.hosts_allowed):
+ self.connection.shutdown(1)
+ return
+
data = self.rfile.read(int(self.headers["content-length"]))
rsp = self.server._marshaled_dispatch(data)
class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
allow_reuse_address = True
- def __init__(self, addr, requestHandler=XMLRPCRequestHandler,
+ def __init__(self, addr, allowed, requestHandler=None,
logRequests = 1):
- SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests)
+ if requestHandler is None:
+ requestHandler = XMLRPCRequestHandler
+ SimpleXMLRPCServer.__init__(self, addr,
+ (lambda x, y, z:
+ requestHandler(allowed, x, y, z)),
+ logRequests)
flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
class UnixXMLRPCServer(TCPXMLRPCServer):
address_family = socket.AF_UNIX
- def __init__(self, addr, logRequests = 1):
+ def __init__(self, addr, allowed, logRequests = 1):
parent = os.path.dirname(addr)
if os.path.exists(parent):
os.chown(parent, os.geteuid(), os.getegid())
os.unlink(addr)
else:
os.makedirs(parent, stat.S_IRWXU)
- TCPXMLRPCServer.__init__(self, addr, UnixXMLRPCRequestHandler,
- logRequests)
+
+ TCPXMLRPCServer.__init__(self, addr, allowed,
+ UnixXMLRPCRequestHandler, logRequests)
from errno import EAGAIN, EINTR, EWOULDBLOCK
+from xen.xend.XendLogging import log
+
"""General classes to support server and client sockets, without
specifying what kind of socket they are. There are subclasses
for TCP and unix-domain sockets (see tcp.py and unix.py).
Accepts connections and runs a thread for each one.
"""
- def __init__(self, protocol_class, hosts_allow = ''):
+ def __init__(self, protocol_class):
self.protocol_class = protocol_class
self.sock = self.createSocket()
threading.Thread(target=self.main).start()
break
finally:
self.close()
+
+
+def hostAllowed(addrport, hosts_allowed):
+ if hosts_allowed is None:
+ return True
+ else:
+ fqdn = socket.getfqdn(addrport[0])
+ for h in hosts_allowed:
+ if h.match(fqdn) or h.match(addrport[0]):
+ return True
+ log.warn("Rejected connection from %s (%s).", addrport[0], fqdn)
+ return False
def acceptConnection(self, sock, addrport):
addr = addrport[0]
- if self.hosts_allow is None:
- connection.SocketServerConnection(sock, self.protocol_class)
+ if connection.hostAllowed(addrport, self.hosts_allow):
+ connection.SocketServerConnection(sock, self.protocol_class)
else:
- fqdn = socket.getfqdn(addr)
- for h in self.hosts_allow:
- if h.match(fqdn) or h.match(addr):
- log.debug("Match %s %s", fqdn, h.pattern)
- connection.SocketServerConnection(sock,
- self.protocol_class)
- return
-
try:
- log.warn("Rejected connection from %s:%d (%s) for port %d.",
- addr, addrport[1], fqdn, self.port)
sock.close()
except:
pass
"""Default level of information to be logged."""
loglevel_default = 'DEBUG'
+ """Default Xen-API server configuration. """
+ xen_api_server_default = [['unix']]
+
"""Default for the flag indicating whether xend should run an http server
(deprecated)."""
xend_http_server_default = 'no'
except Exception:
raise XendError("invalid xend config %s: expected int: %s" % (name, v))
+ def get_xen_api_server(self):
+ """Get the Xen-API server configuration.
+ """
+ return self.get_config_value('xen-api-server',
+ self.xen_api_server_default)
+
def get_xend_http_server(self):
"""Get the flag indicating whether xend should run an http server.
"""
# todo Support command-line args.
import fcntl
+import re
import time
import signal
from threading import Thread
log.info('unix path=' + path)
servers.add(UnixHttpServer(root, path))
+ api_cfg = xroot.get_xen_api_server()
+ if api_cfg:
+ try:
+ addrs = [(str(x[0]).split(':'),
+ len(x) > 1 and x[1] and map(re.compile, x[1].split(" "))
+ or None)
+ for x in api_cfg]
+ for addrport, allowed in addrs:
+ if len(addrport) == 1:
+ if addrport[0] == 'unix':
+ servers.add(XMLRPCServer(allowed = allowed))
+ else:
+ servers.add(XMLRPCServer(True, '', int(addrport[0]),
+ allowed = allowed))
+ else:
+ addr, port = addrport
+ servers.add(XMLRPCServer(True, addr, int(port),
+ allowed = allowed))
+ except ValueError:
+ log.error('Xen-API server configuration %s is invalid' % api_cfg)
+ except TypeError:
+ log.error('Xen-API server configuration %s is invalid' % api_cfg)
+
if xroot.get_xend_tcp_xmlrpc_server():
servers.add(XMLRPCServer(True))
class XMLRPCServer:
def __init__(self, use_tcp=False, host = "localhost", port = 8006,
- path = XML_RPC_SOCKET):
+ path = XML_RPC_SOCKET, hosts_allowed = None):
self.use_tcp = use_tcp
self.port = port
self.host = host
self.path = path
+ self.hosts_allowed = hosts_allowed
self.ready = False
self.running = True
def run(self):
if self.use_tcp:
+ log.info("Opening TCP XML-RPC server on %s%d.",
+ self.host and '%s:' % self.host or
+ 'all interfaces, port ',
+ self.port)
self.server = TCPXMLRPCServer((self.host, self.port),
+ self.hosts_allowed,
logRequests = False)
else:
- self.server = UnixXMLRPCServer(self.path, logRequests = False)
+ log.info("Opening Unix domain socket XML-RPC server on %s:%d.",
+ self.path)
+ self.server = UnixXMLRPCServer(self.path, self.hosts_allowed,
+ logRequests = False)
# Register Xen API Functions
# -------------------------------------------------------------------